home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / util / moni / Scout-src.lha / source / objects / scout_tasks.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-09-17  |  40.7 KB  |  1,160 lines

  1. /**
  2.  * Scout - The Amiga System Monitor
  3.  *
  4.  *------------------------------------------------------------------
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * You must not use this source code to gain profit of any kind!
  21.  *
  22.  *------------------------------------------------------------------
  23.  *
  24.  * @author Andreas Gelhausen
  25.  * @author Richard Körber <rkoerber@gmx.de>
  26.  */
  27.  
  28. #include "system_headers.h"
  29.  
  30. struct TasksCallbackUserData {
  31.     APTR ud_List;
  32.     ULONG ud_Count;
  33. };
  34.  
  35. struct CPUCheckChangeMessage {
  36.     ULONG methodID;
  37.     ULONG value;
  38. };
  39.  
  40. BOOL timer_ticking = FALSE;
  41.  
  42. struct ScoutPatchSemaphore {
  43.     struct SignalSemaphore sps_Semaphore;
  44.     ULONG sps_SemaphoreSize;
  45.     UWORD sps_Version;
  46.     UWORD sps_Revision;
  47.     UBYTE sps_SemaphoreName[32];
  48.     ULONG sps_CodeSize;
  49.     ULONG sps_Reserved[5];
  50.     UBYTE sps_Code[1];
  51. };
  52.  
  53. struct ScoutPatchSemaphore *patchsem = NULL;
  54.  
  55. VOID __asm (*cleartaskdata) (VOID) = NULL;
  56. LONG  __asm (*gettaskdata) (register __d0 struct Task *) = NULL;
  57. struct Task * __asm (*getaddedtask) (VOID) = NULL;
  58. char  *switchstate = NULL;
  59.  
  60. LONG totalmicros,cpuseconds = 1,cpumicros = 0;
  61.  
  62. #define SCOUT_SEMA_NAME         "« Scout's CPU patch »"
  63. #define CHEATTASK_STACKSIZE     1024
  64. #define CHEATTASK_NAME          "« Scout's cheat task »"
  65. struct Task *cheattask = NULL;
  66.  
  67. static __asm __saveds LONG taskslist_con2func(register __a2 Object *obj, register __a1 struct NList_ConstructMessage *msg, register __a0 struct Hook *hook)
  68. {
  69.     return AllocListEntry(msg->pool, msg->entry, sizeof(struct TaskEntry));
  70. }
  71.  
  72. MakeHook(taskslist_con2hook, taskslist_con2func);
  73.  
  74. static __asm __saveds LONG taskslist_des2func(register __a2 Object *obj, register __a1 struct NList_DestructMessage *msg, register __a0 struct Hook *hook)
  75. {
  76.     FreeListEntry(msg->pool, &msg->entry);
  77.  
  78.     return 0;
  79. }
  80.  
  81. MakeHook(taskslist_des2hook, taskslist_des2func);
  82.  
  83. static __asm __saveds LONG taskslist_dsp2func(register __a2 Object *obj, register __a1 struct NList_DisplayMessage *msg, register __a0 struct Hook *hook)
  84. {
  85.     struct TaskEntry *te = (struct TaskEntry *)msg->entry;
  86.  
  87.     if (te) {
  88.         msg->strings[0] = te->te_Address;
  89.         msg->strings[1] = te->te_Name;
  90.         msg->strings[2] = te->te_CPU;
  91.         msg->strings[3] = te->te_Type;
  92.         msg->strings[4] = te->te_Pri;
  93.         msg->strings[5] = te->te_Num;
  94.         msg->strings[6] = te->te_State;
  95.         msg->strings[7] = te->te_SigWait;
  96.         msg->strings[8] = te->te_FreeStack;
  97.     } else {
  98.         msg->strings[0] = "Address";
  99.         msg->strings[1] = "ln_Name";
  100.         msg->strings[2] = "CPU %";
  101.         msg->strings[3] = "ln_Type";
  102.         msg->strings[4] = "ln_Pri";
  103.         msg->strings[5] = "NUM";
  104.         msg->strings[6] = "State";
  105.         msg->strings[7] = "SigWait";
  106.         msg->strings[8] = "Free Stack";
  107.         msg->preparses[0] = MUIX_B;
  108.         msg->preparses[1] = MUIX_B;
  109.         msg->preparses[2] = MUIX_B;
  110.         msg->preparses[3] = MUIX_B;
  111.         msg->preparses[4] = MUIX_B;
  112.         msg->preparses[5] = MUIX_B;
  113.         msg->preparses[6] = MUIX_B;
  114.         msg->preparses[7] = MUIX_B;
  115.         msg->preparses[8] = MUIX_B;
  116.     }
  117.  
  118.     return 0;
  119. }
  120.  
  121. MakeHook(taskslist_dsp2hook, taskslist_dsp2func);
  122.  
  123. static LONG taskslist_cmp2colfunc( struct TaskEntry *te1,
  124.                                    struct TaskEntry *te2,
  125.                                    ULONG column )
  126. {
  127.     LONG pri1, pri2;
  128.  
  129.     switch (column) {
  130.         case 0: return stricmp(te1->te_Address, te2->te_Address);
  131.         case 1: return stricmp(te1->te_Name, te2->te_Name);
  132.         case 2: return stricmp(te1->te_CPU, te2->te_CPU);
  133.         case 3: return stricmp(te1->te_Type, te2->te_Type);
  134.         case 4: IsDec(te1->te_Pri, &pri1); IsDec(te2->te_Pri, &pri2); return pri2 - pri1;
  135.         case 5: return stricmp(te1->te_Num, te2->te_Num);
  136.         case 6: return stricmp(te1->te_State, te2->te_State);
  137.         case 7: return stricmp(te1->te_SigWait, te2->te_SigWait);
  138.         case 8: return stricmp(te1->te_FreeStack, te2->te_FreeStack);
  139.     }
  140. }
  141.  
  142. static __asm __saveds LONG taskslist_cmp2func(register __a2 Object *obj, register __a1 struct NList_CompareMessage *msg, register __a0 struct Hook *hook)
  143. {
  144.     LONG cmp;
  145.     struct TaskEntry *te1, *te2;
  146.     ULONG col1, col2;
  147.  
  148.     te1 = (struct TaskEntry *)msg->entry1;
  149.     te2 = (struct TaskEntry *)msg->entry2;
  150.  
  151.     col1 = msg->sort_type & MUIV_NList_TitleMark_ColMask;
  152.     col2 = msg->sort_type2 & MUIV_NList_TitleMark2_ColMask;
  153.  
  154.     if (msg->sort_type == MUIV_NList_SortType_None) return 0;
  155.  
  156.     if (msg->sort_type & MUIV_NList_TitleMark_TypeMask) {
  157.         cmp = taskslist_cmp2colfunc(te2, te1, col1);
  158.     } else {
  159.         cmp = taskslist_cmp2colfunc(te1, te2, col1);
  160.     }
  161.  
  162.     if (cmp != 0 || col1 == col2) return cmp;
  163.  
  164.     if (msg->sort_type2 & MUIV_NList_TitleMark2_TypeMask) {
  165.         cmp = taskslist_cmp2colfunc(te2, te1, col2);
  166.     } else {
  167.         cmp = taskslist_cmp2colfunc(te1, te2, col2);
  168.     }
  169.  
  170.     return cmp;
  171. }
  172.  
  173. MakeHook(taskslist_cmp2hook, taskslist_cmp2func);
  174.  
  175. static __asm __saveds void cpuinterval_callfunc( register __a0 struct Hook *hook,
  176.                                                  register __a2 Object *obj,
  177.                                                  register __a1 UBYTE **contents )
  178. {
  179.     struct TasksWinData *twd = INST_DATA(OCLASS(obj), obj);
  180.     ULONG i;
  181.     LONG micros = 0;
  182.     UBYTE text[8];
  183.  
  184.     stccpy(text, *contents, sizeof(text));
  185.  
  186.     i = 0;
  187.     while (text[i] != '\0' && text[i] != '.') i++;
  188.  
  189.     if (text[i] == '.') {
  190.         ULONG t, j;
  191.  
  192.         t = 1;
  193.         text[i] = '\0';
  194.         while (isdigit(text[++i])) {
  195.             if (j = (ULONG)(text[i] - '0')) {
  196.                 t *= 10;
  197.                 micros += (1000000 / t) * j;
  198.             }
  199.         }
  200.     }
  201.  
  202.     cpumicros = micros;
  203.     cpuseconds = atol((char *)&text);
  204.     strcpy(updatetimetext, *contents);
  205.  
  206.     if (twd->twd_TimerHandlerAdded) {
  207.         DoMethod(twd->twd_Application, MUIM_Application_RemInputHandler, &twd->twd_TimerHandler);
  208.         twd->twd_TimerHandler.ihn_Millis = (cpuseconds * 1000) + (cpumicros / 1000);
  209.         DoMethod(twd->twd_Application, MUIM_Application_AddInputHandler, &twd->twd_TimerHandler);
  210.     }
  211. }
  212.  
  213. MakeHook(cpuinterval_callhook, cpuinterval_callfunc);
  214.  
  215. static __asm __saveds ULONG realstring_editfunc( register __a0 struct Hook *hook, register __a2 struct SGWork *sgw, register __a1 ULONG *msg )
  216. {
  217.     ULONG return_code;
  218.     ULONG i = 0, punkte = 0, notzeros = 0;
  219.  
  220.     return_code = ~0L;
  221.  
  222.     if (*msg == SGH_KEY) {
  223.         if (sgw->EditOp == EO_REPLACECHAR || sgw->EditOp == EO_INSERTCHAR) {
  224.             while (sgw->WorkBuffer[i]) {
  225.                 if (sgw->WorkBuffer[i++] == '.') punkte++;
  226.             }
  227.             if (punkte > 1 || (!isdigit(sgw->Code) && sgw->Code != '.')) {
  228.                 sgw->Actions |= SGA_BEEP;
  229.                 sgw->Actions &= ~SGA_USE;
  230.             }
  231.         } else if (sgw->EditOp == EO_ENTER) {
  232.             while (sgw->WorkBuffer[i]) {
  233.                 if (sgw->WorkBuffer[i] >= '1' && sgw->WorkBuffer[i] <= '9') notzeros++;
  234.                 i++;
  235.             }
  236.             if (notzeros > 0) {
  237.                 sgw->Actions |= SGA_BEEP;
  238.                 sgw->Actions &= ~SGA_END;
  239.             }
  240.         }
  241.     } else {
  242.         return_code = 0;
  243.     }
  244.  
  245.     return return_code;
  246. }
  247.  
  248. MakeHook(realstring_edithook, realstring_editfunc);
  249.  
  250. static void cheattask_func( void )
  251. {
  252.    while (TRUE) {}
  253. }
  254.  
  255. static struct Task *AddCheatTask( void )
  256. {
  257.     struct Task *result;
  258.  
  259.     if (result = tbAllocVecPooled(globalPool, CHEATTASK_STACKSIZE + sizeof(struct Task))) {
  260.         result->tc_SPLower = (void *)(sizeof(struct Task) + (ULONG)result);
  261.         result->tc_SPUpper = (void *)(CHEATTASK_STACKSIZE + sizeof(struct Task) + (ULONG)result);
  262.         result->tc_SPReg = result->tc_SPUpper;
  263.  
  264.         result->tc_Node.ln_Name = CHEATTASK_NAME;
  265.         result->tc_Node.ln_Pri = -128;
  266.         result->tc_Node.ln_Type = NT_TASK;
  267.  
  268.         AddTask(result, (APTR)&cheattask_func, NULL);
  269.     }
  270.  
  271.     return result;
  272. }
  273.  
  274. static void RemoveCheatTask( void )
  275. {
  276.     if (cheattask) {
  277.         RemTask(cheattask);
  278.         tbFreeVecPooled(globalPool, cheattask);
  279.         cheattask = NULL;
  280.     }
  281. }
  282.  
  283. struct Task *TaskExists( struct Task *tasktofind )
  284. {
  285.     struct Task *task, *result = NULL;
  286.  
  287.     if (tasktofind == myprocess) return myprocess;
  288.  
  289.     Forbid();
  290.  
  291.     ITERATE_LIST(&SysBase->TaskReady, struct Task *, task) {
  292.         if (task == tasktofind) {
  293.             result = task;
  294.             break;
  295.         }
  296.     }
  297.  
  298.     if (result == NULL) {
  299.         ITERATE_LIST(&SysBase->TaskWait, struct Task *, task) {
  300.             if (task == tasktofind) {
  301.                 result = task;
  302.                 break;
  303.             }
  304.         }
  305.     }
  306.  
  307.     Permit();
  308.  
  309.     return result;
  310. }
  311.  
  312. UBYTE *GetTaskState( UBYTE state,
  313.                      ULONG waitmask )
  314. {
  315.     switch (state) {
  316.         case TS_FROZEN:  return txtTaskStateFrozen;
  317.         case TS_ADDED:   return txtTaskStateAdded;
  318.         case TS_RUN:     return txtTaskStateRunning;
  319.         case TS_READY:   return txtTaskStateReady;
  320.         case TS_WAIT:
  321.             switch (waitmask) {
  322.                 case SIGF_ABORT:       return txtTaskStateWaitAbort;
  323.                 case SIGF_CHILD:       return txtTaskStateWaitChild;
  324.                 case SIGF_SINGLE:      return txtTaskStateWaitSemaphore;
  325.                 case SIGF_INTUITION:   return txtTaskStateWaitIntuition;
  326.                 case SIGF_NET:         return txtTaskStateWaitNet;
  327.                 case SIGF_DOS:         return txtTaskStateWaitDOS;
  328.                 case SIGBREAKF_CTRL_C: return txtTaskStateWaitBreakC;
  329.                 case SIGBREAKF_CTRL_D: return txtTaskStateWaitBreakD;
  330.                 case SIGBREAKF_CTRL_E: return txtTaskStateWaitBreakE;
  331.                 case SIGBREAKF_CTRL_F: return txtTaskStateWaitBreakF;
  332.                 case 0x00000000:       return txtTaskStateSuspended;
  333.                 default:               return txtTaskStateWaiting;
  334.             }
  335.         case TS_EXCEPT:  return txtTaskStateExcept;
  336.         case TS_REMOVED: return txtTaskStateRemoved;
  337.         case TS_INVALID: return txtTaskStateInvalid;
  338.         default:         return txtTaskStateUnknown;
  339.     }
  340. }
  341.  
  342. UBYTE *GetNodeType( UBYTE type )
  343. {
  344.     switch (type) {
  345.         case NT_TASK:         return txtNodeTypeTask;
  346.         case NT_INTERRUPT:    return txtNodeTypeInterrupt;
  347.         case NT_DEVICE:       return txtNodeTypeDevice;
  348.         case NT_MSGPORT:      return txtNodeTypeMsgPort;
  349.         case NT_MESSAGE:      return txtNodeTypeMessage;
  350.         case NT_FREEMSG:      return txtNodeTypeFreeMsg;
  351.         case NT_REPLYMSG:     return txtNodeTypeReplyMsg;
  352.         case NT_RESOURCE:     return txtNodeTypeResource;
  353.         case NT_LIBRARY:      return txtNodeTypeLibrary;
  354.         case NT_MEMORY:       return txtNodeTypeMemory;
  355.         case NT_SOFTINT:      return txtNodeTypeSoftInt;
  356.         case NT_FONT:         return txtNodeTypeFont;
  357.         case NT_PROCESS:      return txtNodeTypeProcess;
  358.         case NT_SEMAPHORE:    return txtNodeTypeSemaphore;
  359.         case NT_SIGNALSEM:    return txtNodeTypeSignalSem;
  360.         case NT_BOOTNODE:     return txtNodeTypeBootNode;
  361.         case NT_KICKMEM:      return txtNodeTypeKickMem;
  362.         case NT_GRAPHICS:     return txtNodeTypeGraphics;
  363.         case NT_DEATHMESSAGE: return txtNodeTypeDeathMessage;
  364.         case NT_USER:         return txtNodeTypeUser;
  365.         case NT_EXTENDED:     return txtNodeTypeExtended;
  366.         case NT_UNKNOWN:      return txtNodeTypeUnknown;
  367.         default:              return txtNodeTypeInvalid;
  368.     };
  369. }
  370.  
  371. UBYTE *GetTaskName( struct Task *task,
  372.                     UBYTE *buffer,
  373.                     ULONG maxlen )
  374. {
  375.    buffer[0] = 0x00;
  376.  
  377.    if (task) {
  378.         struct Process *pr = (struct Process *)task;
  379.  
  380.         if (task->tc_Node.ln_Type == NT_PROCESS && pr->pr_CLI != (BPTR)NULL) {
  381.             struct CommandLineInterface *cli= (struct CommandLineInterface *)BADDR(pr->pr_CLI);
  382.  
  383.             if (cli->cli_Module != (BPTR)NULL && cli->cli_CommandName != (BPTR)NULL) {
  384.                 b2cstrn(cli->cli_CommandName, buffer, maxlen);
  385.             }
  386.         }
  387.  
  388.         if ((task->tc_Node.ln_Type == NT_PROCESS || task->tc_Node.ln_Type == NT_TASK) && task->tc_Node.ln_Succ != NULL) {
  389.             ULONG l;
  390.  
  391.             if ((l = strlen(buffer)) > 0) {
  392.                 _snprintf(buffer + l, maxlen - l, " [%s]", nonetest(task->tc_Node.ln_Name));
  393.             } else {
  394.                 stccpy(buffer, nonetest(task->tc_Node.ln_Name), maxlen);
  395.             }
  396.         } else {
  397.             stccpy(buffer, txtNoTask, maxlen);
  398.         }
  399.     } else {
  400.         stccpy(buffer, nonetest(NULL), maxlen);
  401.     }
  402.  
  403.     return buffer;
  404. }
  405.  
  406. static void GetCPUUsage( struct Task *task,
  407.                          struct TaskEntry *te )
  408. {
  409.     if (totalmicros = *((ULONG *) ((ULONG)&TotalMicros1 + 4 - (ULONG)&MySwitch + CodeAddress))) {
  410.         ULONG cpu, zehntel;
  411.  
  412.         cpu = (*gettaskdata)(task);
  413.  
  414.         zehntel = UDivMod32(totalmicros, 10000);
  415.         if (zehntel == 0) zehntel = 1;
  416.  
  417.         zehntel = UDivMod32(cpu, zehntel);
  418.         cpu = UDivMod32(zehntel, 100);
  419.         zehntel -= UMult32(cpu, 100);
  420.         if (cpu > 99) {
  421.             cpu = 100;
  422.             zehntel = 0;
  423.         }
  424.         _snprintf(te->te_CPU, sizeof(te->te_CPU), "%3ld.%02ld", cpu, zehntel);
  425.     }
  426. }
  427.  
  428. static void UpdateTaskEntry( struct Task *task,
  429.                              struct TaskEntry *te,
  430.                              BOOL cpuflag )
  431. {
  432.     _snprintf(te->te_Pri, sizeof(te->te_Pri), "%4ld", task->tc_Node.ln_Pri);
  433.     stccpy(te->te_State, GetTaskState((UBYTE)task->tc_State, task->tc_SigWait), sizeof(te->te_State));
  434.     _snprintf(te->te_SigWait, sizeof(te->te_SigWait), "$%08lx", task->tc_SigWait);
  435.  
  436.     if ((ULONG)task->tc_SPUpper >= (ULONG)task->tc_SPReg &&
  437.         (ULONG)task->tc_SPReg   >= (ULONG)task->tc_SPLower) {
  438.         LONG stackFree;
  439.  
  440.         stackFree = (ULONG)task->tc_SPReg - (ULONG)task->tc_SPLower;
  441.         if (stackFree >= 512) {
  442.             _snprintf(te->te_FreeStack, sizeof(te->te_FreeStack), "%8lD", stackFree);
  443.         } else {
  444.             _snprintf(te->te_FreeStack, sizeof(te->te_FreeStack), MUIX_PH "%8lD" MUIX_PT, stackFree);
  445.         }
  446.     } else {
  447.         // Stackpointer is out of limits, this program is most probably an AmigaE program
  448.         stccpy(te->te_FreeStack, MUIX_PH "---" MUIX_PT, sizeof(te->te_FreeStack));
  449.     }
  450.  
  451.     stccpy(te->te_CPU, "  0.00", sizeof(te->te_CPU));
  452.  
  453.     if (cpuflag && patchsem != NULL) GetCPUUsage(task, te);
  454. }
  455.  
  456. static void GetTaskEntry( struct Task *task,
  457.                           struct TaskEntry *te,
  458.                           BOOL cpuflag )
  459. {
  460.     te->te_Addr = task;
  461.  
  462.     _snprintf(te->te_Address, sizeof(te->te_Address), "$%08lx", task);
  463.     GetTaskName(task, te->te_Name, sizeof(te->te_Name));
  464.     healstring(te->te_Name);
  465.     stccpy(te->te_Type, GetNodeType(task->tc_Node.ln_Type), sizeof(te->te_Type));
  466.  
  467.     if (task->tc_Node.ln_Type == NT_TASK || ((struct Process *)task)->pr_TaskNum == 0) {
  468.         stccpy(te->te_Num, "---", sizeof(te->te_Num));
  469.     } else {
  470.         _snprintf(te->te_Num, sizeof(te->te_Num), "%3ld", ((struct Process *)task)->pr_TaskNum);
  471.     }
  472.  
  473.     UpdateTaskEntry(task, te, cpuflag);
  474. }
  475.  
  476. static void ReceiveList( void (* callback)( struct TaskEntry *te, void *userData ),
  477.                          void *userData )
  478. {
  479.     struct TaskEntry *te;
  480.  
  481.     if (te = tbAllocVecPooled(globalPool, sizeof(struct TaskEntry))) {
  482.         if (SendDaemon("GetTaskList")) {
  483.             while (ReceiveDecodedEntry((UBYTE *)te, sizeof(struct TaskEntry))) {
  484.                 callback(te, userData);
  485.             }
  486.         }
  487.  
  488.         tbFreeVecPooled(globalPool, te);
  489.     }
  490. }
  491.  
  492. static void IterateList( void (* callback)( struct TaskEntry *te, void *userData ),
  493.                          void *userData )
  494. {
  495.     struct MinList tmplist;
  496.     struct TaskEntry *te, *_te;
  497.     struct Task *task;
  498.  
  499.     NewList((struct List *)&tmplist);
  500.  
  501.     Forbid();
  502.  
  503.     if (te = AllocVec(sizeof(struct TaskEntry), MEMF_PUBLIC)) {
  504.         GetTaskEntry(SysBase->ThisTask, te, FALSE);
  505.         AddTail((struct List *)&tmplist, (struct Node *)te);
  506.     }
  507.  
  508.     ITERATE_LIST(&SysBase->TaskReady, struct Task *, task) {
  509.         if (te = AllocVec(sizeof(struct TaskEntry), MEMF_PUBLIC)) {
  510.             GetTaskEntry(task, te, FALSE);
  511.             AddTail((struct List *)&tmplist, (struct Node *)te);
  512.         }
  513.     }
  514.  
  515.     ITERATE_LIST(&SysBase->TaskWait, struct Task *, task) {
  516.         if (te = AllocVec(sizeof(struct TaskEntry), MEMF_PUBLIC)) {
  517.             GetTaskEntry(task, te, FALSE);
  518.             AddTail((struct List *)&tmplist, (struct Node *)te);
  519.         }
  520.     }
  521.  
  522.     Permit();
  523.  
  524.     ITERATE_CHANGING_LIST(&tmplist, struct TaskEntry *, te, _te) {
  525.         callback(te, userData);
  526.         FreeVec(te);
  527.     }
  528. }
  529.  
  530. static void UpdateCallback( struct TaskEntry *te,
  531.                             void *userData )
  532. {
  533.     struct TasksCallbackUserData *ud = (struct TasksCallbackUserData *)userData;
  534.  
  535.     InsertSortedEntry(ud->ud_List, te);
  536.     ud->ud_Count++;
  537. }
  538.  
  539. static void PrintCallback( struct TaskEntry *te,
  540.                            void *userData )
  541. {
  542.     PrintFOneLine((BPTR)userData, " %s %-7.7s %4s %3s %-7.7s %s %s\n", te->te_Address, te->te_Type, te->te_Pri, te->te_Num, te->te_State, te->te_SigWait, te->te_Name);
  543. }
  544.  
  545. static void SendCallback( struct TaskEntry *te,
  546.                           void *userData )
  547. {
  548.     SendEncodedEntry((UBYTE *)te, sizeof(struct TaskEntry));
  549. }
  550.  
  551. static ULONG __saveds mNew( struct IClass *cl,
  552.                             Object *obj,
  553.                             struct opSet *msg )
  554. {
  555.     static UBYTE *CYA_CpuUsageText[] = { NULL, NULL, NULL, NULL };
  556.  
  557.     APTR taskslist, taskstext, taskscount, freezeButton, activateButton, signalButton, breakButton, updateButton, printButton, removeButton, priorityButton, moreButton, exitButton;
  558.     APTR cpucount, cpuCycle, taskstext2;
  559.  
  560.     CYA_CpuUsageText[0] = txtCPUOff;
  561.     CYA_CpuUsageText[1] = txtCPUFull;
  562.     CYA_CpuUsageText[2] = txtCPUPercent;
  563.  
  564.     if (obj = (Object *)DoSuperNew(cl, obj,
  565.         MUIA_HelpNode, TasksText,
  566.         MUIA_Window_ID, MakeID('T','A','S','K'),
  567.         WindowContents, VGroup,
  568.  
  569.             Child, taskslist = MyNListviewObject(MakeID('T','A','L','V'), "BAR,BAR,BAR P=" MUIX_R ",BAR P=" MUIX_C ",BAR P=" MUIX_R ",BAR P=" MUIX_R ",BAR P=" MUIX_C ",BAR,BAR P=" MUIX_R, &taskslist_con2hook, &taskslist_des2hook, &taskslist_dsp2hook, &taskslist_cmp2hook, TRUE),
  570.             Child, MyBelowListview(&taskstext, &taskscount),
  571.  
  572.             Child, MyVSpace(4),
  573.  
  574.             Child, HGroup, MUIA_Group_SameSize, TRUE,
  575.                 Child, printButton    = MakeButton(txtPrint),
  576.                 Child, freezeButton   = MakeButton(txtFreeze),
  577.                 Child, activateButton = MakeButton(txtActivate),
  578.                 Child, HGroup,
  579.                     Child, MyLabel2(" CPU:"),
  580.                     Child, cpucount = GaugeObject,
  581.                         MUIA_Frame, MUIV_Frame_Gauge,
  582.                         MUIA_Gauge_Horiz, TRUE,
  583.                         MUIA_Gauge_Max, 100,
  584.                         MUIA_Gauge_InfoText, MUIX_PT "-----",
  585.                         MUIA_Gauge_Current, 0,
  586.                     End,
  587.                 End,
  588.                 Child, cpuCycle = CycleObject,
  589.                     MUIA_CycleChain, TRUE,
  590.                     MUIA_Weight, 0,
  591.                     MUIA_Cycle_Entries, CYA_CpuUsageText,
  592.                     MUIA_Cycle_Active, (opts.CpuDisplay) ? *opts.CpuDisplay : 0,
  593.                 End,
  594.                 Child, HGroup,
  595.                     Child, MyLabel2(txtSeconds),
  596.                     Child, taskstext2 = StringObject,
  597.                         StringFrame,
  598.                         MUIA_CycleChain, TRUE,
  599.                         MUIA_String_BufferPos, 0,
  600.                         MUIA_String_MaxLen, 6,
  601.                         MUIA_String_EditHook, &realstring_edithook,
  602.                         MUIA_String_Contents, updatetimetext,
  603.                         MUIA_String_Format, MUIV_String_Format_Center,
  604.                     End,
  605.                 End,
  606.             End,
  607.             Child, HGroup, MUIA_Group_SameSize, TRUE,
  608.                 Child, updateButton   = MakeButton(txtUpdate),
  609.                 Child, removeButton   = MakeButton(txtRemove),
  610.                 Child, signalButton   = MakeButton(txtSignal),
  611.                 Child, breakButton    = MakeButton(txtBreak),
  612.                 Child, priorityButton = MakeButton(txtPriority),
  613.                 Child, moreButton     = MakeButton(txtMore),
  614.                 Child, exitButton     = MakeButton(txtExit),
  615.             End,
  616.         End,
  617.         TAG_MORE, msg->ops_AttrList))
  618.     {
  619.         struct TasksWinData *twd = INST_DATA(cl, obj);
  620.         APTR parent;
  621.  
  622.         twd->twd_TaskList = taskslist;
  623.         twd->twd_TaskText = taskstext;
  624.         twd->twd_TaskCount = taskscount;
  625.         twd->twd_RemoveButton = removeButton;
  626.         twd->twd_PriorityButton = priorityButton;
  627.         twd->twd_MoreButton = moreButton;
  628.         twd->twd_SignalButton = signalButton;
  629.         twd->twd_BreakButton = breakButton;
  630.         twd->twd_FreezeButton = freezeButton;
  631.         twd->twd_ActivateButton = activateButton;
  632.         twd->twd_CPUGauge = cpucount;
  633.         twd->twd_CPUCycle = cpuCycle;
  634.         twd->twd_CPUCheck = (opts.CpuDisplay) ? *opts.CpuDisplay : 0;
  635.         twd->twd_RefreshString = taskstext;
  636.         twd->twd_TimerHandler.ihn_Object = obj;
  637.         twd->twd_TimerHandler.ihn_Flags = MUIIHNF_TIMER;
  638.         twd->twd_TimerHandler.ihn_Millis = (cpuseconds * 1000) + (cpumicros / 1000);
  639.         twd->twd_TimerHandler.ihn_Method = MUIM_TasksWin_CPUCheckQuick;
  640.         twd->twd_TimerHandlerAdded = FALSE;
  641.  
  642.         parent = (APTR)GetTagData(MUIA_Window_ParentWindow, (ULONG)NULL, msg->ops_AttrList);
  643.         get(parent, MUIA_ApplicationObject, &twd->twd_Application);
  644.  
  645.         set(obj, MUIA_Window_Title, MyGetWindowTitle("TASKS & PROCESSES", twd->twd_Title, sizeof(twd->twd_Title)));
  646.         set(obj, MUIA_Window_ActiveObject, taskslist);
  647.         set(removeButton, MUIA_Disabled, TRUE);
  648.         set(priorityButton, MUIA_Disabled, TRUE);
  649.         set(moreButton, MUIA_Disabled, TRUE);
  650.         set(freezeButton, MUIA_Disabled, TRUE);
  651.         set(activateButton, MUIA_Disabled, TRUE);
  652.         set(signalButton, MUIA_Disabled, TRUE);
  653.         set(breakButton, MUIA_Disabled, TRUE);
  654.         if (clientstate) {
  655.             set(cpuCycle, MUIA_Disabled, TRUE);
  656.             set(taskstext2, MUIA_Disabled, TRUE);
  657.         }
  658.  
  659.         DoMethod(parent,         MUIM_Window_AddChildWindow, obj);
  660.         DoMethod(obj,            MUIM_Notify, MUIA_Window_CloseRequest, TRUE,           MUIV_Notify_Application, 5, MUIM_Application_PushMethod, parent, 2, MUIM_Window_RemChildWindow, obj);
  661.         DoMethod(taskslist,      MUIM_Notify, MUIA_NList_Active,        MUIV_EveryTime, obj,                     1, MUIM_TasksWin_ListChange);
  662.         DoMethod(taskslist,      MUIM_Notify, MUIA_NList_DoubleClick,   MUIV_EveryTime, obj,                     1, MUIM_TasksWin_More);
  663.         DoMethod(updateButton,   MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Update);
  664.         DoMethod(printButton,    MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Print);
  665.         DoMethod(removeButton,   MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Remove);
  666.         DoMethod(moreButton,     MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_More);
  667.         DoMethod(priorityButton, MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Priority);
  668.         DoMethod(freezeButton,   MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Freeze);
  669.         DoMethod(activateButton, MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Activate);
  670.         DoMethod(signalButton,   MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Signal);
  671.         DoMethod(breakButton,    MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_TasksWin_Break);
  672.         DoMethod(exitButton,     MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     3, MUIM_Set, MUIA_Window_CloseRequest, TRUE);
  673.         DoMethod(cpuCycle,       MUIM_Notify, MUIA_Cycle_Active,        MUIV_EveryTime, obj,                     2, MUIM_TasksWin_CPUCheckChange, MUIV_TriggerValue);
  674.         DoMethod(taskstext2,     MUIM_Notify, MUIA_String_Acknowledge,  MUIV_EveryTime, obj,                     3, MUIM_CallHook, &cpuinterval_callhook, MUIV_TriggerValue);
  675.         DoMethod(taskslist,      MUIM_NList_Sort3, MUIV_NList_Sort3_SortType_1, MUIV_NList_SortTypeAdd_None, MUIV_NList_Sort3_SortType_Both);
  676.         // DoMethod(taskslist,      MUIM_NList_Sort3, spalte, MUIV_NList_SortTypeAdd_None, MUIV_NList_Sort3_SortType_Both);
  677.     }
  678.  
  679.     return (ULONG)obj;
  680. }
  681.  
  682. static ULONG __saveds mDispose( struct IClass *cl,
  683.                                 Object *obj,
  684.                                 struct opSet *msg )
  685. {
  686.     struct TasksWinData *twd = INST_DATA(cl, obj);
  687.  
  688.     if (twd->twd_TimerHandlerAdded) {
  689.         DoMethod(twd->twd_Application, MUIM_Application_RemInputHandler, &twd->twd_TimerHandler);
  690.         twd->twd_TimerHandlerAdded = FALSE;
  691.     }
  692.  
  693.     set(obj, MUIA_Window_Open, FALSE);
  694.     DoMethod(twd->twd_TaskList, MUIM_NList_Clear);
  695.  
  696.     RemoveCheatTask();
  697.  
  698.     return (DoSuperMethodA(cl, obj, msg));
  699. }
  700.  
  701. static ULONG __saveds mUpdate( struct IClass *cl,
  702.                                Object *obj,
  703.                                Msg msg )
  704. {
  705.     struct TasksWinData *twd = INST_DATA(cl, obj);
  706.     struct TasksCallbackUserData ud;
  707.  
  708.     ApplicationSleep(TRUE);
  709.     set(twd->twd_TaskList, MUIA_NList_Quiet, TRUE);
  710.     DoMethod(twd->twd_TaskList, MUIM_NList_Clear);
  711.  
  712.     ud.ud_List = twd->twd_TaskList;
  713.     ud.ud_Count = 0;
  714.  
  715.     if (clientstate) {
  716.         ReceiveList(UpdateCallback, &ud);
  717.     } else {
  718.         IterateList(UpdateCallback, &ud);
  719.     }
  720.  
  721.     SetCountText(twd->twd_TaskCount, ud.ud_Count);
  722.     MySetContents(twd->twd_TaskText, "");
  723.  
  724.     set(twd->twd_TaskList, MUIA_NList_Quiet, FALSE);
  725.     set(twd->twd_TaskList, MUIA_NList_Active, MUIV_NList_Active_Off);
  726.     set(twd->twd_PriorityButton, MUIA_Disabled, TRUE);
  727.     set(twd->twd_RemoveButton, MUIA_Disabled, TRUE);
  728.     set(twd->twd_MoreButton, MUIA_Disabled, TRUE);
  729.     set(twd->twd_FreezeButton, MUIA_Disabled, TRUE);
  730.     set(twd->twd_ActivateButton, MUIA_Disabled, TRUE);
  731.     set(twd->twd_SignalButton, MUIA_Disabled, TRUE);
  732.     set(twd->twd_BreakButton, MUIA_Disabled, TRUE);
  733.  
  734.     DoMethod(obj, MUIM_TasksWin_CPUCheckChange, twd->twd_CPUCheck);
  735.  
  736.     ApplicationSleep(FALSE);
  737.  
  738.     return 0;
  739. }
  740.  
  741. static ULONG __saveds mPrint( struct IClass *cl,
  742.                               Object *obj,
  743.                               Msg msg )
  744. {
  745.     PrintTasks(NULL);
  746.  
  747.     return 0;
  748. }
  749.  
  750. static ULONG __saveds mRemove( struct IClass *cl,
  751.                                Object *obj,
  752.                                Msg msg )
  753. {
  754.     struct TasksWinData *twd = INST_DATA(cl, obj);
  755.     struct TaskEntry *te;
  756.  
  757.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  758.         if (MyRequest(msgYesNo, msgWantToRemoveTask, te->te_Type, te->te_Name)) {
  759.             BOOL withPorts;
  760.  
  761.             withPorts = MyRequest(msgYesNo, msgWantToRemoveTaskWithStuff, te->te_Name);
  762.  
  763.             MyDoCommand("RemoveTask %s %s", te->te_Address, (withPorts) ? "WITHPORTS" : "");
  764.             DoMethod(obj, MUIM_TasksWin_Update);
  765.         }
  766.     }
  767.  
  768.     return 0;
  769. }
  770.  
  771. static ULONG __saveds mPriority( struct IClass *cl,
  772.                                  Object *obj,
  773.                                  Msg msg )
  774. {
  775.     struct TasksWinData *twd = INST_DATA(cl, obj);
  776.     struct TaskEntry *te;
  777.  
  778.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  779.         LONG pri;
  780.  
  781.         pri = atol(te->te_Pri);
  782.         if (GetPriority(te->te_Name, &pri)) {
  783.             if (MyDoCommand("SetTaskPri %s %ld", te->te_Address, pri)) {
  784.                 _snprintf(te->te_Pri, sizeof(te->te_Pri), "%4ld", pri);
  785.                 RedrawActiveEntry(twd->twd_TaskList);
  786.             }
  787.         }
  788.     }
  789.  
  790.     return 0;
  791. }
  792.  
  793. static ULONG __saveds mMore( struct IClass *cl,
  794.                              Object *obj,
  795.                              Msg msg )
  796. {
  797.     struct TasksWinData *twd = INST_DATA(cl, obj);
  798.     struct TaskEntry *te;
  799.  
  800.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  801.         struct Task *task;
  802.         Forbid();
  803.  
  804.         if (task = MyFindTask(te->te_Address)) {
  805.             APTR detailWin;
  806.  
  807.             if (detailWin = TasksDetailWindowObject,
  808.                     MUIA_Window_ParentWindow, obj,
  809.                     MUIA_Window_MaxChildWindowCount, (opts.SingleWindows) ? 1 : 0,
  810.                 End) {
  811.                 set(detailWin, MUIA_TasksDetailWin_Task, te);
  812.                 set(detailWin, MUIA_Window_Open, TRUE);
  813.             }
  814.  
  815.             Permit();
  816.         } else {
  817.             Permit();
  818.  
  819.             MyRequest(msgErrorContinue, msgCantFindTask);
  820.             DoMethod(obj, MUIM_TasksWin_Update);
  821.         }
  822.     }
  823.  
  824.     return 0;
  825. }
  826.  
  827. static ULONG __saveds mListChange( struct IClass *cl,
  828.                                    Object *obj,
  829.                                    Msg msg )
  830. {
  831.     struct TasksWinData *twd = INST_DATA(cl, obj);
  832.     struct TaskEntry *te;
  833.  
  834.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  835.         MySetContents(twd->twd_TaskText, "%s \"%s\"", te->te_Address, te->te_Name);
  836.         set(twd->twd_PriorityButton, MUIA_Disabled, FALSE);
  837.         set(twd->twd_RemoveButton, MUIA_Disabled, FALSE);
  838.         if (!clientstate) {
  839.             set(twd->twd_MoreButton, MUIA_Disabled, FALSE);
  840.             set(twd->twd_CPUCycle, MUIA_Disabled, FALSE);
  841.         }
  842.         set(twd->twd_FreezeButton, MUIA_Disabled, FALSE);
  843.         set(twd->twd_ActivateButton, MUIA_Disabled, FALSE);
  844.         set(twd->twd_SignalButton, MUIA_Disabled, FALSE);
  845.         set(twd->twd_BreakButton, MUIA_Disabled, FALSE);
  846.     }
  847.  
  848.     return 0;
  849. }
  850.  
  851. static ULONG __saveds mFreeze( struct IClass *cl,
  852.                                Object *obj,
  853.                                Msg msg )
  854. {
  855.     struct TasksWinData *twd = INST_DATA(cl, obj);
  856.     struct TaskEntry *te;
  857.  
  858.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  859.         MyDoCommand("FreezeTask %s", te->te_Address);
  860.         stccpy(te->te_State, GetTaskState(TS_FROZEN, 0), sizeof(te->te_State));
  861.         RedrawActiveEntry(twd->twd_TaskList);
  862.     }
  863.  
  864.     return 0;
  865. }
  866.  
  867. static ULONG __saveds mActivate( struct IClass *cl,
  868.                                  Object *obj,
  869.                                  Msg msg )
  870. {
  871.     struct TasksWinData *twd = INST_DATA(cl, obj);
  872.     struct TaskEntry *te;
  873.  
  874.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  875.         MyDoCommand("ActivateTask %s", te->te_Address);
  876.         stccpy(te->te_State, GetTaskState(TS_WAIT, -1), sizeof(te->te_State));
  877.         RedrawActiveEntry(twd->twd_TaskList);
  878.     }
  879.  
  880.     return 0;
  881. }
  882.  
  883. static ULONG __saveds mSignal( struct IClass *cl,
  884.                                Object *obj,
  885.                                Msg msg )
  886. {
  887.     struct TasksWinData *twd = INST_DATA(cl, obj);
  888.     struct TaskEntry *te;
  889.  
  890.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  891.         ULONG sigs;
  892.         APTR sigwin;
  893.  
  894.         IsUHex(te->te_SigWait, &sigs);
  895.         if (sigwin = SignalWindowObject,
  896.                 MUIA_Window_ParentWindow, obj,
  897.             End) {
  898.             if (DoMethod(sigwin, MUIM_SignalWin_GetSignals, te->te_Name, &sigs)) {
  899.                 if (MyDoCommand("SignalTask %s $%08lx", te->te_Address, sigs)) {
  900.                     Delay(25);
  901.                     RedrawActiveEntry(twd->twd_TaskList);
  902.                 } else {
  903.                     DoMethod(obj, MUIM_TasksWin_Update);
  904.                 }
  905.             }
  906.         }
  907.     }
  908.  
  909.     return 0;
  910. }
  911.  
  912. static ULONG __saveds mBreak( struct IClass *cl,
  913.                               Object *obj,
  914.                               Msg msg )
  915. {
  916.     struct TasksWinData *twd = INST_DATA(cl, obj);
  917.     struct TaskEntry *te;
  918.  
  919.     if (te = (struct TaskEntry *)GetActiveEntry(twd->twd_TaskList)) {
  920.         if (MyDoCommand("BreakTask %s", te->te_Address)) {
  921.             Delay(25);
  922.             RedrawActiveEntry(twd->twd_TaskList);
  923.         } else {
  924.             DoMethod(obj, MUIM_TasksWin_Update);
  925.         }
  926.     }
  927.  
  928.     return 0;
  929. }
  930.  
  931. static ULONG __saveds mCPUCheckChange( struct IClass *cl,
  932.                                        Object *obj,
  933.                                        Msg msg )
  934. {
  935.     struct TasksWinData *twd = INST_DATA(cl, obj);
  936.     struct CPUCheckChangeMessage *cccm = (struct CPUCheckChangeMessage *)msg;
  937.  
  938.     twd->twd_CPUCheck = cccm->value;
  939.  
  940.     if (cccm->value != 0) {
  941.         ULONG semasize, codesize;
  942.  
  943.         Forbid();
  944.         patchsem = (struct ScoutPatchSemaphore *)FindSemaphore(SCOUT_SEMA_NAME);
  945.         Permit();
  946.  
  947.         codesize = (ULONG)&CodeAddress - (ULONG)&MySwitch + 8;
  948.         semasize = sizeof(struct ScoutPatchSemaphore) + codesize;
  949.  
  950.         if (patchsem != NULL &&
  951.             patchsem->sps_SemaphoreSize == semasize &&
  952.             patchsem->sps_CodeSize == codesize &&
  953.             ((patchsem->sps_Version > version_ulong) || (patchsem->sps_Version == version_ulong && patchsem->sps_Revision >= revision_ulong))) {
  954.             CodeAddress = &patchsem->sps_Code[0];
  955.         } else {
  956.             struct ScoutPatchSemaphore *sps;
  957.  
  958.             if (patchsem) {
  959.                 void (*switch_func)( void ) = (void (*)())OldSwitch;
  960.  
  961.                 MyRequest(msgErrorContinue, msgFoundOldPatchSemaphore, patchsem->sps_Version, patchsem->sps_Revision, version_ulong, revision_ulong);
  962.                 Disable();
  963.                 *switchstate = 0;
  964.                 *((ULONG *)(-52 + (ULONG)SysBase)) = OldSwitch;
  965.                 *((ULONG *)(-280 + (ULONG)SysBase)) = OldAddTask;
  966.                 switch_func();
  967.                 sps = patchsem;
  968.                 patchsem = NULL;
  969.                 Enable();
  970.                 RemSemaphore(sps);
  971.                 FreeMem(sps, sps->sps_SemaphoreSize);
  972.             }
  973.  
  974.             AsmTimerBase = TimerIORequest->tr_node.io_Device;
  975.  
  976.             if (sps = AllocMem(semasize, MEMF_ANY | MEMF_PUBLIC | MEMF_REVERSE)) {
  977.                 CodeAddress = &sps->sps_Code[0];
  978.                 OldSwitch = *((ULONG *)(-52 + (ULONG)SysBase));
  979.                 OldAddTask = *((ULONG *)(-280 + (ULONG)SysBase));
  980.  
  981.                 // der Code darf erst nach dem Auslesen der Sprünge passieren, sonst werden für den Assembler-Teil falsche Adressen kopiert
  982.                 CopyMem(&MySwitch, sps->sps_Code, codesize);
  983.  
  984.                 InitSemaphore(sps);
  985.                 sps->sps_Semaphore.ss_Link.ln_Name = &sps->sps_SemaphoreName[0];
  986.                 stccpy(sps->sps_SemaphoreName, SCOUT_SEMA_NAME, sizeof(sps->sps_SemaphoreName));
  987.                 sps->sps_SemaphoreSize = semasize;
  988.                 sps->sps_Version = version_ulong;
  989.                 sps->sps_Revision = revision_ulong;
  990.                 sps->sps_CodeSize = codesize;
  991.                 AddSemaphore(sps);
  992.  
  993.                 SetPatches();
  994.  
  995.                 patchsem = sps;
  996.             } else {
  997.                 MyRequest(msgErrorContinue, msgCantInstallPatchSemaphore);
  998.             }
  999.         }
  1000.     }
  1001.  
  1002.     if (patchsem) {
  1003.         cleartaskdata = (void (* __asm)(void))((char *)&ClearTaskData - (char *)&MySwitch + CodeAddress);
  1004.         gettaskdata = (LONG (* __asm)(register __d0 struct Task *))((char *)&GetTaskData - (char *)&MySwitch + CodeAddress);
  1005.         getaddedtask = (struct Task * (* __asm)(void))((char *)&GetAddedTask - (char *)&MySwitch + CodeAddress);
  1006.         switchstate = (char *)&SwitchState - (char *)&MySwitch + CodeAddress;
  1007.  
  1008.         *switchstate = (char)cccm->value;
  1009.         // HandleTimerRequest(FALSE);
  1010.         (*cleartaskdata)();
  1011.  
  1012.         if (cccm->value == 2) {
  1013.             if (!cheattask) cheattask = AddCheatTask();
  1014.         } else {
  1015.             RemoveCheatTask();
  1016.             set(twd->twd_CPUGauge, MUIA_Gauge_Current, 0);
  1017.             set(twd->twd_CPUGauge, MUIA_Gauge_InfoText, MUIX_PT "-----");
  1018.         }
  1019.  
  1020.         // DoMethod(obj, MUIM_TasksWin_CPUCheck);
  1021.  
  1022.         if (cccm->value == 0) {
  1023.             if (twd->twd_TimerHandlerAdded) {
  1024.                 DoMethod(twd->twd_Application, MUIM_Application_RemInputHandler, &twd->twd_TimerHandler);
  1025.                 twd->twd_TimerHandlerAdded = FALSE;
  1026.             }
  1027.         } else {
  1028.             if (!twd->twd_TimerHandlerAdded) {
  1029.                 DoMethod(twd->twd_Application, MUIM_Application_AddInputHandler, &twd->twd_TimerHandler);
  1030.                 twd->twd_TimerHandlerAdded = TRUE;
  1031.             }
  1032.         }
  1033.  
  1034.         DoMethod(obj, MUIM_TasksWin_CPUCheck);
  1035.     }
  1036.  
  1037.     return 0;
  1038. }
  1039.  
  1040. static ULONG __saveds mCPUCheck( struct IClass *cl,
  1041.                                  Object *obj,
  1042.                                  Msg msg )
  1043. {
  1044.     struct TasksWinData *twd = INST_DATA(cl, obj);
  1045.     struct TasksCallbackUserData ud;
  1046.     struct Task *task;
  1047.     BOOL changed;
  1048.     ULONG i, oldTaskCnt, sortCol;
  1049.  
  1050.     get(twd->twd_TaskList, MUIA_NList_Entries, &oldTaskCnt);
  1051.     get(twd->twd_TaskList, MUIA_NList_SortType, &sortCol);
  1052.     sortCol &= MUIV_NList_TitleMark_ColMask;
  1053.  
  1054.     ud.ud_List = twd->twd_TaskList;
  1055.     ud.ud_Count = oldTaskCnt;
  1056.  
  1057.     (*cleartaskdata)();
  1058.  
  1059.     while (task = (*getaddedtask)()) {
  1060.         if (TaskExists(task)) {
  1061.             GetTaskEntry(task, &twd->twd_NewEntry, (twd->twd_CPUCheck != 0));
  1062.             UpdateCallback(&twd->twd_NewEntry, &ud);
  1063.         }
  1064.     }
  1065.  
  1066.     changed = FALSE;
  1067.  
  1068.     for (i = 0; ; i++) {
  1069.         struct TaskEntry *old;
  1070.  
  1071.         DoMethod(twd->twd_TaskList, MUIM_NList_GetEntry, i, &old);
  1072.  
  1073.         if (old) {
  1074.             if (task = TaskExists(old->te_Addr)) {
  1075.                 CopyMem(old, &twd->twd_CompareEntry, sizeof(struct TaskEntry));
  1076.                 UpdateTaskEntry(task, old, twd->twd_CPUCheck);
  1077.                 if (memcmp(old, &twd->twd_CompareEntry, sizeof(struct TaskEntry))) {
  1078.                     if (sortCol != 2) DoMethod(twd->twd_TaskList, MUIM_NList_Redraw, i);
  1079.                     changed = TRUE;
  1080.                 }
  1081.             } else {
  1082.                 DoMethod(twd->twd_TaskList, MUIM_NList_Remove, i);
  1083.                 i--;
  1084.                 ud.ud_Count--;
  1085.             }
  1086.         } else {
  1087.             break;
  1088.         }
  1089.     }
  1090.  
  1091.     if (ud.ud_Count != oldTaskCnt) SetCountText(twd->twd_TaskCount, ud.ud_Count);
  1092.     if (changed && sortCol == 2) DoMethod(twd->twd_TaskList, MUIM_List_Sort);
  1093.  
  1094.     if (twd->twd_CPUCheck == 2) {
  1095.         ULONG cheatcpu;
  1096.  
  1097.         cheatcpu = (*gettaskdata)(cheattask);
  1098.         if (totalmicros) {
  1099.             set(twd->twd_CPUGauge, MUIA_Gauge_InfoText, "%ld%%");
  1100.             set(twd->twd_CPUGauge, MUIA_Gauge_Current, UDivMod32(UMult32(totalmicros - cheatcpu, 100), totalmicros));
  1101.         }
  1102.     }
  1103.  
  1104.     return 0;
  1105. }
  1106.  
  1107. static ULONG __saveds mCPUCheckQuick( struct IClass *cl,
  1108.                                       Object *obj,
  1109.                                       Msg msg )
  1110. {
  1111.     if (patchsem != NULL && *switchstate != 0) {
  1112.         DoMethod(obj, MUIM_TasksWin_CPUCheck);
  1113.     }
  1114.  
  1115.     return TRUE;
  1116. }
  1117.  
  1118. ULONG __asm __saveds TasksWinDispatcher( register __a0 struct IClass *cl,
  1119.                                                register __a2 Object *obj,
  1120.                                                register __a1 Msg msg )
  1121. {
  1122.     switch (msg->MethodID) {
  1123.         case OM_NEW:                       return (mNew(cl, obj, (APTR)msg));
  1124.         case OM_DISPOSE:                   return (mDispose(cl, obj, (APTR)msg));
  1125.         case MUIM_TasksWin_Update:         return (mUpdate(cl, obj, (APTR)msg));
  1126.         case MUIM_TasksWin_Print:          return (mPrint(cl, obj, (APTR)msg));
  1127.         case MUIM_TasksWin_Remove:         return (mRemove(cl, obj, (APTR)msg));
  1128.         case MUIM_TasksWin_Priority:       return (mPriority(cl, obj, (APTR)msg));
  1129.         case MUIM_TasksWin_More:           return (mMore(cl, obj, (APTR)msg));
  1130.         case MUIM_TasksWin_ListChange:     return (mListChange(cl, obj, (APTR)msg));
  1131.         case MUIM_TasksWin_Freeze:         return (mFreeze(cl, obj, (APTR)msg));
  1132.         case MUIM_TasksWin_Activate:       return (mActivate(cl, obj, (APTR)msg));
  1133.         case MUIM_TasksWin_Signal:         return (mSignal(cl, obj, (APTR)msg));
  1134.         case MUIM_TasksWin_Break:          return (mBreak(cl, obj, (APTR)msg));
  1135.         case MUIM_TasksWin_CPUCheckChange: return (mCPUCheckChange(cl, obj, (APTR)msg));
  1136.         case MUIM_TasksWin_CPUCheck:       return (mCPUCheck(cl, obj, (APTR)msg));
  1137.         case MUIM_TasksWin_CPUCheckQuick:  return (mCPUCheckQuick(cl, obj, (APTR)msg));
  1138.     }
  1139.  
  1140.     return (DoSuperMethodA(cl, obj, msg));
  1141. }
  1142.  
  1143. void PrintTasks( char *filename )
  1144. {
  1145.     BPTR handle;
  1146.  
  1147.     if (handle = HandlePrintStart(filename)) {
  1148.         PrintFOneLine(handle, "\n  Address  Type     Pri NUM State    SigWait  Name\n\n");
  1149.         IterateList(PrintCallback, (void *)handle);
  1150.     }
  1151.  
  1152.     HandlePrintStop();
  1153. }
  1154.  
  1155. void SendTaskList( void )
  1156. {
  1157.     IterateList(SendCallback, NULL);
  1158. }
  1159.  
  1160.